global_asm!(include_str!("trap.S"));

pub fn init() {
    extern "C" { fn __alltraps(); }
    unsafe {
        stvec::write(__alltraps as usize, TrapMode::Direct);
    }
}

#[no_mangle]
pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
    let scause = scause::read();
    let stval = stval::read();

    match scause.cause() {
        Trap::Exception(Exception::UserEnvCall) => {
            cx.sepc += 4;
            cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
        }
        Trap::Exception(Exception::StoreFault) |
            Trap::Exception(Exception::StorePageFault) {
                println!("[kernel] PageFault in application");
                run_next_app();
            }
        Trap::Exception(Exception::IllegalInstruction) => {
            println!("[kernel] IllegalInstruction");
            run_next_app();
        }
        _ => {
            panic!("Unsupported trap {:?}, stvel {:#x}!", cx, stval);
        }
    }

    cx
}
